package com.quectel.mobile.controller.pay;

import cn.hutool.http.ContentType;
import com.quectel.business.pay.PayBusiness;
import com.quectel.business.pay.handler.BasePayHandler;
import com.quectel.business.pay.handler.model.BusinessIntegrityCheckStrategy;
import com.quectel.constant.global.SystemConstants;
import com.quectel.mobile.controller.BaseController;
import com.quectel.pay.module.merchant.dto.PayChannelDto;
import com.quectel.pay.module.order.constants.OrderConstants;
import com.quectel.pay.module.order.dto.PayOrderDto;
import com.quectel.pay.module.order.dto.PayOrderRefundDto;
import com.quectel.pay.module.order.dto.response.NotifyCheckResult;
import com.quectel.pay.module.order.service.*;
import com.quectel.sdk.pay.PayNotifyResponse;
import com.quectel.util.common.Response;
import com.quectel.util.http.RequestUtils;
import com.quectel.util.redis.RedisUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.io.IOUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.locks.Lock;

/**
 * @author cl
 */
@RestController
@RequestMapping("payNotify")
@Tag(name = "PayNotifyController", description = "支付回调相关")
public class PayNotifyController extends BaseController {

    @DubboReference
    private OrderWechatAppPayService orderWechatAppPayService;
    @DubboReference
    private OrderWechatJSAPIPayService orderWechatJSAPIPayService;
    @DubboReference
    private OrderAliAppPayService orderAliAppPayService;
    @DubboReference
    private OrderAliJSAPIPayService orderAliJSAPIPayService;
    @DubboReference
    private PayOrderService orderService;
    @DubboReference
    private PayOrderRefundService orderRefundService;

    @Autowired
    private PayBusiness payBusiness;


    @PostMapping("wxRefundNotify/{version}/{terminalType}/{payChannelId}")
    @Operation(summary = "微信jsapi/app退款成功回调")
    public void wxRefundNotify(@PathVariable String version, @PathVariable Byte terminalType, @PathVariable Long payChannelId, HttpServletRequest req, HttpServletResponse response) {

        NotifyCheckResult notifyCheckResult = null;
        try {
            Map<String, String> allHeaders = RequestUtils.getAllHeaders(req);

            ServletInputStream recIn = req.getInputStream();
            String wxRecData = new String(IOUtils.toByteArray(recIn));
            logger.info("Wechat refund notify str:{}", wxRecData);
            if (SystemConstants.TerminalType.JSAPI.getType().equals(terminalType)) {

                notifyCheckResult = orderWechatJSAPIPayService.refundNotifyCheck(payChannelId, allHeaders, wxRecData);
            } else if (SystemConstants.TerminalType.APP.getType().equals(terminalType)) {
                notifyCheckResult = orderWechatAppPayService.refundNotifyCheck(payChannelId, allHeaders, wxRecData);
            }
        } catch (IOException e) {
            logger.error("Refund notify check error", e);
        }
        if (notifyCheckResult == null || !notifyCheckResult.isCheckSuccess()) {
            return;
        }

        try {
            if (notifyCheckResult.isRefundSuccessNotify()) {
                if (!notifyCheckResult.isRefundSuccess()) {
                    return;
                }

                PayOrderRefundDto payOrderRefundDto = orderRefundService.selectByOutRefundNo(notifyCheckResult.getOutRefundNo());


                orderRefundService.signRefundSuccess(payOrderRefundDto.getOutTradeNo(), notifyCheckResult.getOutRefundNo(), notifyCheckResult.getRefundSuccessTime());

                // 向业务通知退款成功
                Response<Object> businessResp = payBusiness.refundSuccessNotify(payOrderRefundDto);
                if (!businessResp.isSuccess()) {
                    writeResponseInfo(SystemConstants.PayType.WX.getType(), version, false, response);
                    return;
                }

                writeResponseInfo(SystemConstants.PayType.WX.getType(), version, true, response);
            }

        } catch (Exception e) {
            // 回复支付平台
            writeResponseInfo(SystemConstants.PayType.WX.getType(), version, false, response);
            logger.error("Hand refund notify failed", e);
        }
    }

    @PostMapping("completeNotify/{payType}/{version}/{terminalType}/{payChannelId}")
    @Operation(summary = "h5支付回调 包括支付宝退款回调")
    public void payCompleteNotify(@PathVariable Byte payType, @PathVariable String version, @PathVariable Byte terminalType, @PathVariable Long payChannelId, HttpServletRequest req, HttpServletResponse response) {

        NotifyCheckResult notifyCheckResult = null;
        if (SystemConstants.PayType.ZFB.getType().equals(payType)) {
            // 支付宝
            notifyCheckResult = orderAliJSAPIPayService.checkNotify(payChannelId, req.getParameterMap());
        } else if (SystemConstants.PayType.WX.getType().equals(payType)) {
            // 微信
            try {
                Map<String, String> allHeaders = RequestUtils.getAllHeaders(req);

                ServletInputStream recIn = req.getInputStream();
                String wxRecData = new String(IOUtils.toByteArray(recIn));
                if (SystemConstants.TerminalType.JSAPI.getType().equals(terminalType)) {
                    notifyCheckResult = orderWechatJSAPIPayService.payNotifyCheck(payChannelId, allHeaders, wxRecData);
                } else if (SystemConstants.TerminalType.APP.getType().equals(terminalType)) {
                    notifyCheckResult = orderWechatAppPayService.payNotifyCheck(payChannelId, allHeaders, wxRecData);
                }
            } catch (IOException e) {
                logger.error("Pay notify check error", e);
            }
        }
        if (notifyCheckResult == null || !notifyCheckResult.isCheckSuccess()) {
            return;
        }
        String outTradeNo = notifyCheckResult.getOutTradeNo();

        try {

            //先判断这次的回调类型是退款还是什么
            if (notifyCheckResult.isPaySuccessNotify()) {
                if (!notifyCheckResult.isPaySuccess()) {
                    return;
                }
                //1加锁
                Lock lock = RedisUtils.getSpinLock("PayNotify" + outTradeNo);
                lock.lock();
                try {
                    PayOrderDto orderDto = orderService.selectByOutTradeNo(outTradeNo);
                    // 然后判断订单状态
                    if (OrderConstants.Status.INIT.getStatusValue().equals(orderDto.getStatus())) {

                        orderDto.setTradeNo(notifyCheckResult.getTradeNo());
                        orderDto.setPayTime(notifyCheckResult.getPaySuccessTime());
                        orderDto.setUpdateTime(new Date());
                        orderDto.setStatus(OrderConstants.Status.PAY_SUCCESS.getStatusValue());

                        // doSomethings
                        Response<Object> businessResp = payBusiness.paySuccessNotify(orderDto);
                        if (!businessResp.isSuccess()) {
                            //3回复支付平台
                            writeResponseInfo(payType, version, false, response);
                            return;
                        }

                        orderService.updateById(orderDto);

                        BasePayHandler basePayHandler = payBusiness.searchHandler(orderDto.getBusinessType());
                        BusinessIntegrityCheckStrategy strategy = basePayHandler.businessIntegrityCheckStrategy();
                        if (strategy.isNeedNotify()) {
                            if (strategy.getDelaySeconds() <= 0) {
                                basePayHandler.businessIntegrityCheckNotify(orderDto);
                            } else {
                                // 向MQ发送延迟消息
                            }
                        }

                        // 回复支付平台
                        writeResponseInfo(payType, version, true, response);
                    }
                } catch (Exception e) {
                    // 回复支付平台
                    writeResponseInfo(payType, version, false, response);
                    logger.error("Hand order failed");
                } finally {
                    lock.unlock();
                }
            }

        } catch (Exception e) {

            // 回复支付平台
            writeResponseInfo(payType, version, false, response);

            //解除锁
            logger.error("Hand order failed");
        }


    }

    /**
     * 响应信息
     *
     * @param payType
     * @param version       针对微信需要确认版本v3回复的内容由xml更改为json
     * @param isHandSuccess
     * @param response
     */
    private void writeResponseInfo(Byte payType, String version, boolean isHandSuccess, HttpServletResponse response) {
        try {
            ServletOutputStream out = response.getOutputStream();
            if (SystemConstants.PayType.ZFB.getType().equals(payType)) {
                //支付宝
                if (isHandSuccess) {
                    out.print(PayNotifyResponse.aliPayHandSuccessStr());
                    out.flush();
                } else {
                    out.print(PayNotifyResponse.aliPayHandFailedStr());
                    out.flush();
                }
            } else if (SystemConstants.PayType.WX.getType().equals(payType)) {
                if (PayChannelDto.WeChatJSAPIChannelConfig.VERSION_V2.equals(version)
                ) {
                    // 微信v2
                    if (isHandSuccess) {
                        out.print(PayNotifyResponse.wechatPayV2HandSuccessStr());
                        out.flush();
                    } else {
                        out.print(PayNotifyResponse.wechatPayV2HandFailedStr());
                        out.flush();
                    }
                } else if (PayChannelDto.WeChatJSAPIChannelConfig.VERSION_V3.equals(version)) {
                    if (isHandSuccess) {
                        response.setStatus(200);
                        response.setHeader("Content-type", ContentType.JSON.toString());
                        out.print(PayNotifyResponse.wechatPayV3HandSuccessStr());
                        out.flush();
                    } else {
                        response.setStatus(200);
                        response.setHeader("Content-type", ContentType.JSON.toString());
                        out.print(PayNotifyResponse.wechatPayV3HandFailedStr());
                        out.flush();
                    }
                }
            }
        } catch (IOException e) {
            logger.info("交易成功回复第三方平台失败");
        }
    }
}
